package com.wwcom.darteagle.model;

import java.util.ArrayList;
import java.util.List;

import android.text.TextUtils;

import com.wwcom.darteagle.R;

public class DartStats {
	private MatchInfo matchInfo;
	private MatchPlayer matchPlayer;
	private int legInd;
	private int setInd;
	
	//Stats Info
	public static final int AVERAGE= 0;
	public static final int FIRST9AVERAGE= 1;
	public static final int HIGHESTSCORE= 2;
	public static final int PLUS60= 3;
	public static final int PLUS100= 4;
	public static final int PLUS140= 5;
	public static final int PLUS180= 6;
	public static final int DOUBLES= 7;
	public static final int CHECKOUTS= 8;
	public static final int HIGHESTCHECKOUT= 9;
	public static final int PLUS50CHECKOUT= 10;
	public static final int PLUS100CHECKOUT= 11;
	public static final int ACCURACY20= 12;
	public static final int ACCURACY19= 13;
	public static final int PERCENTAGE20= 14;
	public static final int PERCENTAGE19= 15;
	public static final int INDIVIDUALDOUBLES= 16;
	
	
	public static final int[] STATS_NAMES = {
		R.string.matchstats_average,
		R.string.matchstats_first_nine_average,	
		R.string.matchstats_highest_score,	
		R.string.matchstats_60_plus,	
		R.string.matchstats_100_plus,	
		R.string.matchstats_140_plus,	
		R.string.matchstats_180s,	
		R.string.matchstats_doubles_percentage,	
		R.string.matchstats_checkout_percentage,	
		R.string.matchstats_highest_checkout,	
		R.string.matchstats_50_plus_checkouts,	
		R.string.matchstats_100_plus_checkouts,	
		R.string.matchstats_accuracy20,	
		R.string.matchstats_accuracy19,
		R.string.matchstats_accuracy_percentage20,
		R.string.matchstats_accuracy_percentage19
	};
	
	//averages
	private RunningAverage average;
	private RunningAverage first9average;
	
	//counts
	private int plus60;
	private int plus100;
	private int plus140;
	private int plus180;
	private int plus50Checkout;
	private int plus100Checkout;
	
	//highest values
	private int highestScore;
	private int highestCheckout;
	
	//percentages
	private RunningPercentage doubles;
	private RunningPercentage trebles;
	private RunningPercentage checkouts;
	private List<RunningPercentage> individualDoubles;
	
	//accuracy stats
	private RunningAverage accuracy20;
	private RunningAverage accuracy19;
	private RunningPercentage percentage20;
	private RunningPercentage percentage19;
	
		
	public DartStats(MatchInfo matchInfo, MatchPlayer matchPlayer, int setInd, int legInd) {
		initialiseSelf();
		this.matchInfo= matchInfo;
		this.matchPlayer= matchPlayer;
		this.legInd= legInd;
		this.setInd= setInd;	
	}
	
	public DartStats(MatchInfo matchInfo, int setInd, int legInd) {
		initialiseSelf();
		this.matchInfo= matchInfo;
		this.legInd= legInd;
		this.setInd= setInd;	
	}
	
	private void initialiseSelf() {
		this.matchInfo= null;
		this.matchPlayer= null;
		plus60= 0;
		plus100= 0;
		plus140= 0;
		plus180= 0;
		plus50Checkout= 0;
		plus100Checkout= 0;
		highestScore= 0;
		highestCheckout= 0;
		average= new RunningAverage();
		first9average= new RunningAverage();
		doubles= new RunningPercentage();
		trebles= new RunningPercentage();
		checkouts= new RunningPercentage();
		individualDoubles= new ArrayList<RunningPercentage>(21);
		for (int i= 0; i < 21; i++) {
			RunningPercentage p= new RunningPercentage();
			individualDoubles.add(p);
		}
		accuracy20= new RunningAverage();
		accuracy19= new RunningAverage();
		percentage20= new RunningPercentage();
		percentage19= new RunningPercentage();
		this.legInd= -1;
		this.setInd= -1;	
	}	
	//accessors
	public int getSetInd() {
		return setInd;
	}

	public void setSetInd(int setInd) {
		this.setInd = setInd;
	}

	public int getLegInd() {
		return legInd;
	}

	public void setLegInd(int legInd) {
		this.legInd = legInd;
	}

	public MatchInfo getMatchInfo() {
		return matchInfo;
	}
	
	public float getAverage() {
		return average.getCurrentAverage();
	}

	public float getAverageTotal() {
		return average.getTotal();
	}

	public int getAverageNDarts() {
		return average.getNDarts();
	}
	
	public void setAverage(float total, int nDarts) {
		average.set(total,nDarts);
	}

	public float getFirst9Average() {
		return first9average.getCurrentAverage();
	}

	public float getFirst9AverageTotal() {
		return first9average.getTotal();
	}

	public int getFirst9AverageNDarts() {
		return first9average.getNDarts();
	}

	public void setFirst9Average(float total, int nDarts) {
		first9average.set(total,nDarts);
	}

	public float getDoublePercentage() {
		return doubles.getCurrentPercentage();
	}

	public int getDoubleAttempts() {
		return doubles.getAttempts();
	}

	public int getDoubleSuccesses() {
		return doubles.getSuccesses();
	}

	public float getIndividualDoublePercentage(int i) {
		return individualDoubles.get(i).getCurrentPercentage();
	}

	public int getIndividualDoubleAttempts(int i) {
		return individualDoubles.get(i).getAttempts();
	}

	public int getIndividualDoubleSuccesses(int i) {
		return individualDoubles.get(i).getSuccesses();
	}

	public void setIndividualDoublesPercentage(int i, int attempts, int successes) {
		individualDoubles.get(i).set(attempts, successes);
	}
	
	
	public void setDoublePercentage(int attempts, int successes) {
		doubles.set(attempts,successes);
	}

	public float getCheckoutPercentage() {
		return checkouts.getCurrentPercentage();
	}

	public int getCheckoutAttempts() {
		return checkouts.getAttempts();
	}

	public int getCheckoutSuccesses() {
		return checkouts.getSuccesses();
	}

	public void setCheckoutPercentage(int attempts, int successes) {
		checkouts.set(attempts,successes);
	}

	public float getAccuracy20Percentage() {
		return percentage20.getCurrentPercentage();
	}

	public int getAccuracy20Attempts() {
		return percentage20.getAttempts();
	}

	public int getAccuracy20Successes() {
		return percentage20.getSuccesses();
	}

	public void setAccuracy20Percentage(int attempts, int successes) {
		percentage20.set(attempts,successes);
	}

	public float getAccuracy20Rating() {
		return accuracy20.getCurrentAverage() * 100.0f;
	}
	
	public void setAccuracy20Rating(float f, int nDarts) {
		accuracy20.set(f,nDarts);
	}
	

	public float getAccuracy19Percentage() {
		return percentage19.getCurrentPercentage();
	}

	public int getAccuracy19Attempts() {
		return percentage19.getAttempts();
	}

	public int getAccuracy19Successes() {
		return percentage19.getSuccesses();
	}

	public void setAccuracy19Percentage(int attempts, int successes) {
		percentage19.set(attempts,successes);
	}

	public float getAccuracy19Rating() {
		return accuracy19.getCurrentAverage() * 100.0f;
	}

	public void setAccuracy19Rating(float total, int nDarts) {
		accuracy19.set(total,nDarts);
	}

	public int getPlus60() {
		return plus60;
	}

	public void setPlus60(int plus60) {
		this.plus60= plus60;
	}

	public int getPlus100() {
		return plus100;
	}	

	public void setPlus100(int plus100) {
		this.plus100= plus100;
	}

	public int getPlus140() {
		return plus140;
	}

	public void setPlus140(int plus140) {
		this.plus140= plus140;
	}

	public int getPlus180() {
		return plus180;
	}
	
	public void setPlus180(int plus180) {
		this.plus180= plus180;
	}

	public int getHighestScore() {
		return highestScore;
	}
	
	public void setHighestScore(int highestScore) {
		this.highestScore= highestScore;
	}

	public int getPlus50Checkout() {
		return plus50Checkout;
	}

	public void setPlus50Checkout(int plus50Checkout) {
		this.plus50Checkout= plus50Checkout;
	}

	public int getPlus100Checkout() {
		return plus100Checkout;
	}

	public void setPlus100Checkout(int plus100Checkout) {
		this.plus100Checkout= plus100Checkout;
	}

	public int getHighestCheckout() {
		return highestCheckout;
	}

	public void setHighestCheckout(int highestCheckout) {
		this.highestCheckout= highestCheckout;
	}

	public MatchPlayer getMatchPlayer() {
		return matchPlayer;
	}

	//add data
	public void addDartStats(VisitScore vs) {
		int visitScore= vs.getVisitScore();
		//counts
		if (visitScore >= 180)
			plus180++;
		else if (visitScore >= 140)
			plus140++;
		else if (visitScore >= 100)
			plus100++;
		else if (visitScore >= 60)
			plus60++;
		
		int newLegScore= vs.getLegScore();
		if (newLegScore == 0) {
			if (visitScore >= 100)
				plus100Checkout++;
			else if (visitScore >= 50)
				plus50Checkout++;
		}
		
		//highest
		if (visitScore > highestScore)
			highestScore= visitScore;
		if (newLegScore == 0 && visitScore > highestCheckout)
			highestCheckout= visitScore;
				
		//fill in unrecorded dartscores (passed in as -1s) with zeros
		boolean legWon= newLegScore==0;
		int[] dartScore= vs.getScore().getDartScore();
		boolean[] isDouble= vs.getScore().getIsDouble();
		boolean[] isTreble= vs.getScore().getIsTreble();
		int lastDart= 0;
		if (!legWon) {  //didn't win leg so threw all darts
			lastDart= dartScore.length;
		} else {  // won leg with last recorded dart
			for (int i= 0; i<dartScore.length; i++) {
				if (dartScore[i] >= 0) {
					lastDart= i+1;
				}
			}
		}
		//fill in any that weren't recorded
		for (int i= 0; i<dartScore.length; i++) {
			if (i < lastDart && dartScore[i] == -1) {
				dartScore[i]= 0;
				isDouble[i]= false;
				isTreble[i]= false;
			}
		}
		
		//averages
		average.addScores(dartScore);
		if (vs.getNumDartsThrown() <= 9) {
			first9average.addScores(dartScore);
		}
		
		//doubles - were we trying to double in?
		int prevLegScore= vs.getPrevLegScore();
		if (matchInfo.isDoubleIn() && prevLegScore == matchInfo.getLegTarget()) {
			doubles.addDarts(isDouble[0]);
			if (!isDouble[0]) {
				doubles.addDarts(isDouble[1]);
				if (!isDouble[1] )
					doubles.addDarts(isDouble[2]);
			}
		}
		//trebles - were we trying to treble in?
		if (matchInfo.isTrebleIn() && prevLegScore == matchInfo.getLegTarget()) {
			trebles.addDarts(isTreble[0]);
			if (!isTreble[0]) {
				trebles.addDarts(isTreble[1]);
				if (!isTreble[1] )
					trebles.addDarts(isTreble[2]);
			}
		}
		
		//doubles - were we trying to double out?		
		if (matchInfo.isDoubleOut()) {
			int prevDartScore= prevLegScore;
			int dInd= 0;
			for (int ds : dartScore) {
				if (ds != -1) {
					if (wasDartAtDouble(prevDartScore,ds,dInd)) {
						if (prevDartScore-ds == 0) //only true if we got the double we needed
							doubles.addDarts(isDouble[dInd]);
						else
							doubles.addDarts(false);
					}
					prevDartScore-= ds;
				}
				dInd++;
			}			
		}
		//trebles - were we trying to treble out?
		if (matchInfo.isTrebleOut()) {
			int prevDartScore= prevLegScore;
			int dInd= 0;
			for (int ds : dartScore) {
				if (ds != -1) {
					if (wasDartAtTreble(prevDartScore)) {
						if (prevDartScore-ds == 0) //only true if we got the double we needed
							trebles.addDarts(isTreble[dInd]);
						else
							trebles.addDarts(false);
					}
					prevDartScore-= ds;
				}
				dInd++;
			}			
		}
		
		//check outs - were we able to checkout?
		//double out
		if (matchInfo.isDoubleOut() && wasDoubleOutCheckoutPossible(prevLegScore) ) {
			checkouts.addDarts(newLegScore==0);
		} else if (matchInfo.isTrebleOut() && wasTrebleOutCheckoutPossible(prevLegScore) ) {
			checkouts.addDarts(newLegScore==0);
		} else if (wasSingleOutCheckoutPossible(prevLegScore) ) {
			checkouts.addDarts(newLegScore==0);			
		}
		
		
		//accuracy - doubles
		// which double were we throwing at?
		if (matchInfo.isDoubleOut()) {
			int prevDartScore= prevLegScore;
			int dInd= 0;
			for (int ds : dartScore) {
				if (ds != -1) {
					if (wasDartAtDouble(prevDartScore,ds,dInd)) {
						int doubleInd= whichDoubleWasDartAt(prevDartScore, ds, dInd);
						if (doubleInd > -1) { //we were going for a double
							if (prevDartScore-ds == 0)  //we hit the double and won th eleg
								individualDoubles.get(doubleInd).addDarts(true);
							else
								individualDoubles.get(doubleInd).addDarts(false);								
						}
					}
					prevDartScore-= ds;
				}
				dInd++;
			}			
		}
		
		//accuracy - 20s
		int prevDartScore= prevLegScore;
		int dInd= 0;
		for (int ds : dartScore) {
			if (ds != -1) {
				int dartScoreSingle= ds;
				if (isDouble[dInd])
					dartScoreSingle/= 2;
				if (isTreble[dInd])
					dartScoreSingle/= 3;
				if (wasDartAt20(prevDartScore, dartScoreSingle)) {
					percentage20.addDarts(dartScoreSingle == 20);
					accuracy20.add(getDartAccuracy(20,dartScoreSingle));
				}
				prevDartScore-= ds;
			}
			dInd++;
		}			

		//accuracy - 19s
		prevDartScore= prevLegScore;
		dInd= 0;
		for (int ds : dartScore) {
			if (ds != -1) {
				int dartScoreSingle= ds;
				if (isDouble[dInd])
					dartScoreSingle/= 2;
				if (isTreble[dInd])
					dartScoreSingle/= 3;
				if (wasDartAt19(prevDartScore, dartScoreSingle)) {
					percentage19.addDarts(dartScoreSingle == 19);
					accuracy19.add(getDartAccuracy(19,dartScoreSingle));
				}
				prevDartScore-= ds;
			}
			dInd++;
		}			
		
	}
	

	private boolean wasDartAtDouble(int scoreLeft, int dartScore, int dartNum) {
		return (dartNum == 2 && scoreLeft == 50) || //special case will only count shots at bull on third dart
				(scoreLeft == 50 && dartScore == 50) || //unless we got it!
				(scoreLeft <= 40 && scoreLeft > 1 && scoreLeft%2 == 0);
	}

	private boolean wasDartAtTreble(int dartScore) {
		return dartScore <= 60 && dartScore > 2 && dartScore%3 == 0;
	}

	private boolean wasSingleOutCheckoutPossible(int legScore) {
		String[] checkout= matchInfo.getCheckout(legScore, 3);
		return checkout != null;
	}

	private boolean wasDoubleOutCheckoutPossible(int legScore) {
		String[] checkout= matchInfo.getCheckout(legScore, 3);
		return checkout != null;
		
/*		if (legScore > 170)
			return false;
		if (legScore < 2)
			return false;
		if (legScore == 169 || legScore == 168 || legScore == 166 ||
				legScore == 165 || legScore == 163 || legScore == 162 ||
				legScore == 159) //bogies
			return false;
		
		return true; */
	}
	
	private boolean wasTrebleOutCheckoutPossible(int legScore) {
		String[] checkout= matchInfo.getCheckout(legScore, 3);
		return checkout != null;
	}

	private int whichDoubleWasDartAt(int scoreLeft, int dartScore, int dartNum) {
		if (dartNum == 2 && scoreLeft == 50) { //only assume we were going for bull if it was the last dart
			return 20;
		} else if (scoreLeft == 50 && dartScore == 50) { //unless we got it on any dart
			return 20;
		} else if (scoreLeft <= 40 && scoreLeft > 1 && scoreLeft%2 == 0) { //if we had a double assume we went for it
			return scoreLeft/2 -1;
		} else {
			return -1;			
		}
	}
	
	private boolean wasDartAt20(int scoreLeft, int dartScoreSingle) {
		if (scoreLeft > 180) {
			if (dartScoreSingle == 20 || 
				dartScoreSingle == 5 || dartScoreSingle == 1 || 
				dartScoreSingle == 12 || dartScoreSingle == 18 || 
				dartScoreSingle == 9 || dartScoreSingle == 4) {
				return true;
			}
		}
		return false;
	}
	
	private boolean wasDartAt19(int scoreLeft, int dartScoreSingle) {
		if (scoreLeft > 180) {
			if (dartScoreSingle == 19 || 
				dartScoreSingle == 7 || dartScoreSingle == 3 || 
				dartScoreSingle == 16 || dartScoreSingle == 17 || 
				dartScoreSingle == 8 || dartScoreSingle == 2) {
				return true;
			}
		}
		return false;
	}

	//base on a gaussian with 1.25 sigma 
	private float getDartAccuracy(int dartTarget, int dartScoreSingle) {		
		if (dartTarget == 20) {
			if (dartScoreSingle == 20) {
				return 1.0f;
			}
			if (dartScoreSingle == 5 || dartScoreSingle == 1) {
				return 0.7f;
			}
			if (dartScoreSingle == 12 || dartScoreSingle == 18) {
				return 0.3f;
			}
			if (dartScoreSingle == 9 || dartScoreSingle == 4) {
				return 0.05f;
			}
		}
		if (dartTarget == 19) {
			if (dartScoreSingle == 19) {
				return 1.0f;
			}
			if (dartScoreSingle == 7 || dartScoreSingle == 3) {
				return 0.7f;
			}
			if (dartScoreSingle == 16 || dartScoreSingle == 17) {
				return 0.3f;
			}
			if (dartScoreSingle == 8 || dartScoreSingle == 2) {
				return 0.05f;
			}
		}
		return 0.0f;
	}
	
	//merge stats together to support overall player stats
	public void merge(DartStats other) {
		//average
		average.addRunningAverage(other.average);
		//first9 average
		first9average.addRunningAverage(other.first9average);
		//highest score
		if (other.highestScore > highestScore)
			highestScore= other.highestScore;
		//plus60, plus100, plus140, plus180
		plus60+= other.plus60;
		plus100+= other.plus100;
		plus140+= other.plus140;
		plus180+= other.plus180;
		//doubles
		doubles.addRunningPercentage(other.doubles);
		//checkouts
		checkouts.addRunningPercentage(other.checkouts);
		//highestCheckout
		if (other.highestCheckout > highestCheckout)
			highestCheckout= other.highestCheckout;
		//plus50Checkout, plut100Checkout
		plus50Checkout+= other.plus50Checkout;
		plus100Checkout+= other.plus100Checkout;
		//accuracy20, accuracy19
		accuracy20.addRunningAverage(other.accuracy20);
		accuracy19.addRunningAverage(other.accuracy19);
		//percentage20,percentage19
		percentage20.addRunningPercentage(other.percentage20);
		percentage19.addRunningPercentage(other.percentage19);
		
		//individual doubles
		for (int i= 0; i<individualDoubles.size(); i++) {
			individualDoubles.get(i).addRunningPercentage(other.individualDoubles.get(i));			
		}
	}	
}
